from catmaConfig import ATTRIB_FLAGS, TYPEID_NONE
import catmaDB
import axiom2

class BaseCheck(object):
    tag = 'base'
    prefix = None

    def __init__(self, runner):
        self._runner = runner



    def CheckForInvalidValues(self, typeInstance, db):
        criticalValues = typeInstance.GetAllValues(None, True, True, True)
        for (valueName, valueInfo,) in criticalValues.iteritems():
            value = valueInfo[0]
            attFlag = valueInfo[1]
            valueRange = valueInfo[2]
            if (value is None):
                if (attFlag & ATTRIB_FLAGS.NOT_NULL):
                    self._runner.ReportError(typeInstance, ('missing value: %s' % valueName))
            elif ((attFlag & ATTRIB_FLAGS.TYPE_REF) and (value != TYPEID_NONE)):
                try:
                    referencedType = db.GetTypeByID(value)
                    checkErrors = self._runner.CheckType(referencedType, db)
                    if checkErrors:
                        self._runner.ReportError(typeInstance, ("referenced catma type '%s' on %s has errors" % (referencedType.GetTypeName(), valueName)))
                    if not referencedType.IsPublished():
                        self._runner.ReportError(typeInstance, ("referenced catma type '%s' on %s is not published" % (referencedType.GetTypeName(), valueName)))
                except catmaDB.CatmaDBError:
                    self._runner.ReportError(typeInstance, ("couldn't find referenced catma type with typeID '%s'on %s" % (value, valueName)))
            if ((valueRange is not None) and (value is not None)):
                (rangeMin, rangeMax,) = valueRange
                if (((rangeMin is not None) and (value < rangeMin)) or ((rangeMax is not None) and (value > rangeMax))):
                    self._runner.ReportError(typeInstance, ("attribute '%s' value '%s' out of range: [%s, %s]" % (valueName,
                     value,
                     rangeMin,
                     rangeMax)))




    def Check(self, db, typeInstance):
        self.CheckForInvalidValues(typeInstance, db)



    def Recognize(self, typeInstance):
        typeName = typeInstance.GetTypeName().lower()
        if self.prefix:
            for pfx in self.prefix:
                if (typeName.find(pfx) == 0):
                    return True

        return False




class VehicleCheck(BaseCheck):
    tag = 'vehicle'
    prefix = ['veh_']

    def Check(self, db, typeInstance):
        super(VehicleCheck, self).Check(db, typeInstance)




class ModuleCheck(BaseCheck):
    tag = 'module'
    prefix = ['imod',
     'vmod',
     'imp']

    def Check(self, db, typeInstance):
        super(ModuleCheck, self).Check(db, typeInstance)




class InstallationCheck(BaseCheck):
    tag = 'installation'
    prefix = ['inst_']

    def Check(self, db, typeInstance):
        super(InstallationCheck, self).Check(db, typeInstance)




class CharacterCheck(BaseCheck):
    tag = 'character'
    prefix = ['char_']

    def Check(self, db, typeInstance):
        super(CharacterCheck, self).Check(db, typeInstance)




class WeaponCheck(BaseCheck):
    tag = 'weapon'
    prefix = ['twpn_', 'wpn_']

    def Check(self, db, typeInstance):
        super(WeaponCheck, self).Check(db, typeInstance)




class EffectorCheck(BaseCheck):
    tag = 'weapon effector'
    prefix = ['eft_']

    def Check(self, db, typeInstance):
        super(EffectorCheck, self).Check(db, typeInstance)




class GameTypeCheck(BaseCheck):
    tag = 'game type'

    def Check(self, db, typeInstance):
        super(GameTypeCheck, self).Check(db, typeInstance)




class TurretCheck(BaseCheck):
    prefix = ['tur_']

    def Check(self, db, typeInstance):
        super(TurretCheck, self).Check(db, typeInstance)




class CheckRunner(object):
    checkClasses = [VehicleCheck,
     ModuleCheck,
     InstallationCheck,
     CharacterCheck,
     WeaponCheck,
     EffectorCheck,
     TurretCheck]

    def __init__(self):
        self._checkedTypes = {}
        self._skippedTypes = []



    def GetNumCheckedTypes(self):
        return len(self._checkedTypes)



    def GetNumSkippedTypes(self):
        return len(self._skippedTypes)



    def GetCheckClass(self, catmaType):
        finalCheck = None
        for checkClass in self.checkClasses:
            check = checkClass(self)
            if check.Recognize(catmaType):
                finalCheck = check
                break

        if (finalCheck is None):
            finalCheck = BaseCheck(self)
        return finalCheck



    def ReportError(self, catmaType, error):
        if (catmaType in self._checkedTypes):
            self._checkedTypes[catmaType].append(error)
        else:
            self._checkedTypes[catmaType] = [error]



    def GetErrors(self):
        allErrors = {}
        for (typeInstance, errors,) in self._checkedTypes.iteritems():
            if errors:
                allErrors[typeInstance] = errors

        return allErrors



    def CheckType(self, typeInstance, db):
        check = self.GetCheckClass(typeInstance)
        if check:
            if (typeInstance not in self._checkedTypes):
                self._checkedTypes[typeInstance] = []
                check.Check(db, typeInstance)
            return self._checkedTypes[typeInstance]
        if (typeInstance not in self._skippedTypes):
            self._skippedTypes.append(typeInstance)



    def CheckAll(self, ax2, pathFilter = None):
        db = catmaDB.CatmaDB()
        dumpValueRangeFlag = ax2.GetFlag('DumpValueRange')
        ax2.SetFlag('DumpValueRange', True)
        ax2.GenerateDB(db, axiom2.EXPORT_ALL, True)
        ax2.SetFlag('DumpValueRange', dumpValueRangeFlag)
        self._checkedTypes = {}
        self._skippedTypes = []
        allTypes = db.GetAllTypes()
        for (typeName, typeInstance,) in allTypes.iteritems():
            fullPath = typeInstance.GetFullyQualifiedPath()
            if ((pathFilter is None) or (pathFilter in fullPath)):
                self.CheckType(typeInstance, db)

        printError = False
        if printError:
            print ('==== %s types checked, %s skipped ====' % (len(self._checkedTypes), len(self._skippedTypes)))
            for (typeInstance, errors,) in self._checkedTypes.iteritems():
                if errors:
                    print '\n'
                    print ('%s:' % typeInstance.GetTypeName())
                    for error in errors:
                        print ('    %s' % error)


            if False:
                print '==== skipped list ===='
                for skippedType in self._skippedTypes:
                    print ('  %s' % skippedType.GetTypeName())





